package com.meevle.red5
{
    import com.meevle.events.Red5ConnectionEvent;
    import com.meevle.events.Red5StreamEvent;
    
    import flash.events.EventDispatcher;
    import flash.events.NetStatusEvent;
    import flash.events.SecurityErrorEvent;
    import flash.media.Microphone;
    import flash.net.NetConnection;
    import flash.net.NetStream;
    import flash.net.ObjectEncoding;
	
	[Event(name="connectSuccess", type="com.meevle.events.Red5ConnectionEvent")]
	[Event(name="disconnected", type="com.meevle.events.Red5ConnectionEvent")]
	[Event(name="publishStart", type="com.meevle.events.Red5StreamEvent")]
	[Event(name="unpublished", type="com.meevle.events.Red5StreamEvent")]
	public class Red5Connection extends EventDispatcher
	{
		private var nc:NetConnection;
		private var ns:NetStream;
		private var uri:String;
		
		public function Red5Connection(uri:String)
		{
			this.uri = uri;
			//  create the netConnection
			nc = new NetConnection();
			//  set it's client/focus to this
			nc.client = this;
			// add listeners for netstatus and security issues
			nc.addEventListener(NetStatusEvent.NET_STATUS, netStatusHandler);
 			nc.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);

	         // set the encoding to AMF0 - still waiting for AMF3 to be implemented on Red5
			nc.objectEncoding = ObjectEncoding.AMF0;
		}
		
		public function connect(username:String, password:String):void {
			if(!nc.connected) {
				nc.connect(getURI(), username, password);
			}
		}
		
		public function publish(streamname:String, mic:Microphone):void {
			if(mic != null) {
				if(nc.connected)
				{
					if(ns != null) {
						ns.close();
						ns = null;
					} 
					ns = new NetStream(nc);
					ns.addEventListener(NetStatusEvent.NET_STATUS, streamStatusHandler);
					ns.attachAudio(mic);
					ns.publish(streamname);
		        }
		 	}
		}
		
		public function close():void
		{
			nc.close();
		}

		public function getURI():String
		{
			return uri;
		}
		
		public function isConnected():Boolean
		{
			return nc.connected;
		}
		
		public function onBWDone():void
	    {
			// have to have this for an RTMP connection
		}

		private function netStatusHandler(event:NetStatusEvent):void
		{
			var e:Red5ConnectionEvent;
			switch(event.info.code)
			{
				case "NetConnection.Connect.Failed":
				e = new Red5ConnectionEvent(Red5ConnectionEvent.CONNECT_FAILED, event.info.code);
	            dispatchEvent(e);
				break;

				case "NetConnection.Connect.Success":
				e = new Red5ConnectionEvent(Red5ConnectionEvent.CONNECT_SUCCESS, event.info.code);
				dispatchEvent(e);
				break;
				
				case "NetConnection.Connect.Rejected":
				e = new Red5ConnectionEvent(Red5ConnectionEvent.CONNECT_REJECTED, event.info.code);
				dispatchEvent(e);
				break;

				case "NetConnection.Connect.Closed":
				e = new Red5ConnectionEvent(Red5ConnectionEvent.CONNECT_CLOSED, event.info.code);
				dispatchEvent(e);
				break;
				
				case "NetConnection.Connect.InvalidApp":
				e = new Red5ConnectionEvent(Red5ConnectionEvent.CONNECT_INVALID_APP, event.info.code);
				dispatchEvent(e);
				break;

				case "NetConnection.Connect.AppShutdown":
				e = new Red5ConnectionEvent(Red5ConnectionEvent.CONNECT_APP_SHUTDOWN, event.info.code);
				dispatchEvent(e);
				break;
			}

			if(event.info.code != "NetConnection.Connect.Success")
			{
				// I dispatch DISCONNECTED incase someone just simply wants to know if we're not connected'
				// rather than having to subscribe to the events individually
				e = new Red5ConnectionEvent(Red5ConnectionEvent.DISCONNECTED, event.info.code);
				dispatchEvent(e);
			}
		}
		
		private function streamStatusHandler(event:NetStatusEvent):void
		{
			var e:Red5StreamEvent;
			switch(event.info.code)
			{
				case "NetStream.Publish.Start":
				e = new Red5StreamEvent(Red5StreamEvent.PUBLISH_START, event.info.code);
	            dispatchEvent(e);
				break;
				
				case "NetStream.Unpublish.Success":
				e = new Red5StreamEvent(Red5StreamEvent.UNPUBLISH_SUCCESS, event.info.code);
	            dispatchEvent(e);
				break;
				
				case "NetStream.Publish.BadName":
				e = new Red5StreamEvent(Red5StreamEvent.PUBLISH_BAD_NAME, event.info.code);
	            dispatchEvent(e);
				break;

			}

			if(event.info.code != "NetStream.Publish.Start")
			{
				// I dispatch UNPUBLISHED incase someone just simply wants to know if we're not publishing'
				// rather than having to subscribe to the events individually
				e = new Red5StreamEvent(Red5StreamEvent.UNPUBLISHED, event.info.code);
				dispatchEvent(e);
			}
		}
		
               
		private function securityErrorHandler(event:SecurityErrorEvent):void
		{
			var e:Red5ConnectionEvent = new Red5ConnectionEvent(Red5ConnectionEvent.SECURITY_ERROR, event.text);
			dispatchEvent(e);
		}
	}
}